package a02;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JPanel;

import util.Pair;

public class RegularBoard<M> extends JPanel implements Constants{

    private static final long serialVersionUID = 1L;
    private Color color1 = Color.RED;
    private Color color2 = Color.BLUE;
    private String colorName1 = "ROT";
    private String colorName2 = "BLAU";

    private RegularGame<M> game;
    private RegularControl<M> control;
    private final int UNIT = 70;
    private boolean blanksActive = false;
    private int gridMode = 0;
    private boolean ticTacToeMode;
    private Pair<Byte, Byte> lastMove = null;

    public void setTicTacToeMode(boolean ticTacToeMode) {
	this.ticTacToeMode = ticTacToeMode;
    }

    private Graphics2D graphics;
    private Color gridColor;

    public Graphics2D getTheGraphics() {
	return graphics;
    }

    public RegularBoard(RegularGame<M> g) {
	this.game = g;
    }

    public RegularGame<M> getGame() {
	return this.game;
    }

    public String getPlayerColorName(byte player) {
	String tmp;
	if (player == this.game.getPlayerOne()) {
	    tmp = colorName1;
	} else if (player == this.game.getPlayerTwo()) {
	    tmp = colorName2;
	} else {
	    tmp = "BLACK";
	}

	return tmp;
    }

    @Override
    public Dimension getPreferredSize() {
	return new Dimension(this.game.getColumns() * this.getUNIT(),
		this.game.getRows() * this.getUNIT());
    }

    public int getUNIT() {
	return UNIT;
    }

    @Override
    public void paintComponent(Graphics g1) {
	super.paintComponent(g1);
	this.graphics = (Graphics2D) g1;

	if(Config.ANTIALIASING) this.graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
		RenderingHints.VALUE_ANTIALIAS_ON);
	if (isGridActive())
	    paintGrid(gridMode, gridColor);
	for (byte c = 0; c < this.game.getColumns(); c++) {
	    for (byte r = 0; r < this.game.getRows(); r++) {
		if (!ticTacToeMode
			&& this.game.getAtPosition(c, r) != this.game
				.getPlayerNone()) {
		    paintStone(c, r);
		} else if (ticTacToeMode // TODO TICTACTOEBOARD OVERRIDE
			&& this.game.getAtPosition(c, r) != this.game
				.getPlayerNone()) {
		    this.paintAdvancedStone(c, r);
		}
	    }
	}
    }

    public void paintAdvancedStone(byte c, byte r) {
	if (this.game.getAtPosition(c, r) == this.game.getPlayerOne()) {
	    this.graphics.setColor(this.selectColor(this.game.getAtPosition(c,
		    r)));
	    this.graphics.fillOval((c * this.getUNIT()) + 5,
		    (r * this.getUNIT()) + 5, (this.getUNIT() - 10),
		    (this.getUNIT() - 10));
	    this.graphics.setColor(Color.WHITE);
	    this.graphics.fillOval((c * this.getUNIT() + 16),
		    (r * this.getUNIT() + 16), (this.getUNIT() - 32),
		    (this.getUNIT()) - 32);
	} else if (this.game.getAtPosition(c, r) == this.game.getPlayerTwo()) {

	    this.graphics.setColor(this.selectColor(this.game.getAtPosition(c,
		    r)));
	    this.graphics.setStroke(new BasicStroke(12, BasicStroke.CAP_ROUND,
		    BasicStroke.JOIN_MITER));
	    this.graphics.drawLine((c * this.getUNIT()) + 15,
		    (r * this.getUNIT()) + 15, (c * this.getUNIT()) + 55,
		    (r * this.getUNIT()) + 55);
	    this.graphics.drawLine((c * this.getUNIT()) + 55,
		    (r * this.getUNIT()) + 15, (c * this.getUNIT()) + 15,
		    (r * this.getUNIT()) + 55);
	}
	paintLastMove(c, r);
    }

    public void paintStone(byte c, byte r) {
	this.graphics.setColor(this.selectColor(this.game.getAtPosition(c, r)));
	this.graphics.fillOval((c * this.getUNIT()) + 2,
		(r * this.getUNIT()) + 2, (this.getUNIT()) - 4,
		(this.getUNIT()) - 4);
	paintLastMove(c, r);
    }

    public void paintLastMove(byte c, byte r) {
	if (!(getLastMove() == null) && c == getLastMove().fst
		&& r == getLastMove().snd) {
	    this.graphics.setColor(Color.GREEN);
	    this.graphics.fillOval((c * this.getUNIT())
		    + ((this.getUNIT() / 2) - 4),
		    (r * this.getUNIT()) + ((this.getUNIT() / 2) - 4),
		    (this.getUNIT()) - ((this.getUNIT() / 2) + 25),
		    (this.getUNIT()) - ((this.getUNIT() / 2) + 25));
	}
    }

    public void paintGrid(int gridMode, Color gridColor) {
	int shifting = 0;
	byte plus = 0;
	if (gridMode == 2) {
	    shifting = (getUNIT() / 2);
	    plus = 1;
	}
	for (byte r = (byte) (1 - plus); r < (this.game.getRows()); r++) {
	    this.graphics.setColor(gridColor);
	    this.graphics.setStroke(new BasicStroke(2 - plus,
		    BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER));
	    this.graphics.drawLine(0 + shifting, (r * this.getUNIT())
		    + shifting,
		    ((this.game.getColumns() - plus) * this.getUNIT())
			    + shifting, (r * this.getUNIT()) + shifting);
	}

	for (byte c = (byte) (1 - plus); c < (this.game.getColumns()); c++) {
	    this.graphics.setStroke(new BasicStroke(2 - plus,
		    BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER));
	    this.graphics.setColor(gridColor);
	    this.graphics.drawLine((c * this.getUNIT()) + shifting,
		    (0 + shifting), (c * this.getUNIT()) + shifting,
		    ((this.game.getRows() - plus) * this.getUNIT()) + shifting);
	}
    }  

    public Color selectColor(byte player) {
	Color tmp;
	if (player == this.game.getPlayerOne()) {
	    tmp = this.color1;
	} else if (player == this.game.getPlayerTwo()) {
	    tmp = this.color2;
	} else {
	    tmp = Color.GREEN;
	}
	return tmp;
    }

    public void setPlayerColors(Color color1, String colorName1, Color color2,
	    String colorName2) {
	this.color1 = color1;
	this.colorName1 = colorName1;
	this.color2 = color2;
	this.colorName2 = colorName2;
    }

    public void setGame(RegularGame<M> g) {
	this.game = g;
	this.repaint();
    }

    public void setTableColor(int r, int g, int b) {
	this.setBackground(new Color(r, g, b));
    }

    public void setTableColor(Color c) {
	this.setBackground(c);
    }

    public boolean isShowBlanksActive() {
	return blanksActive;
    }

    public void setShowBlanksActive(boolean blanksActive) {
	this.blanksActive = blanksActive;
    }

    public boolean isGridActive() {
	return !(gridMode == 0);
    }

    public void setGrid(Color gridColor, int mode) {
	this.gridMode = mode;
	this.gridColor = gridColor;
    }

    public RegularControl<M> getControl() {
	return this.control;
    }

    public void setControl(RegularControl<M> control) {
	this.control = control;
    }

    public Pair<Byte, Byte> getLastMove() {
	return lastMove;
    }

    public void setLastMove(Pair<Byte, Byte> lastMove) {
	this.lastMove = lastMove;
    }

}
